package edu.office.applicationRepository;

import edu.office.entities.Edgeamongknowledge;
import edu.office.entities.Knowledge;
import edu.office.entities.Predicate;
import edu.office.entities.Subject;
import edu.office.tools.StaticFields;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;

import java.util.*;

@Named("edgeAmongKnowledgeRepositoryA")
@ApplicationScoped
public class EdgeAmongKnowledgeRepository extends ApplicationCommonRepository<Edgeamongknowledge> {

    public static int MAXEDGES = 10;
    @Inject
    KnowledgeRepository knowledgeRepository;
    @Inject
    PredicateRepository predicateRepository;

    public List<Edgeamongknowledge> getEdgeamongknowledges4KnowledgePreOrSucc(Integer knowledgeid, int location) {
        List<Edgeamongknowledge> resultList = null;
        if (null == knowledgeid) {
            return new LinkedList<>();
        }
        resultList = switch (location) {
            case StaticFields.PREDCESSOR -> find("successornode", knowledgeid).list();
            case StaticFields.SUCCESSOR -> find("PREDECESSORNODE", knowledgeid).list();
            default -> resultList;
        };
        return resultList;
    }

    public Set<Edgeamongknowledge> getEdgeamongknowledgeList4Subject(Subject subject) {
        Set<Edgeamongknowledge> e = new HashSet<>();
        if (null != subject) {
            List<Knowledge> knowledgesList = knowledgeRepository.getKnowledgeList4Subject(subject);
            for (Knowledge knowledge : knowledgesList) {
                e.addAll(getEdgeamongknowledges4KnowledgePreOrSucc(knowledge.getID(), StaticFields.PREDCESSOR));
                e.addAll(getEdgeamongknowledges4KnowledgePreOrSucc(knowledge.getID(), StaticFields.SUCCESSOR));
            }
        }
        return e;
    }

    public String getString4Dagre(Edgeamongknowledge edge) {
        Predicate predicate = predicateRepository.find("ID", edge.getPREDICATE()).firstResult();
        return "\"" + knowledgeRepository.getString4Dagre(knowledgeRepository.find("ID", edge.getSUCCESSORNODE()).firstResult())
                + "\"->\"" + knowledgeRepository.getString4Dagre(knowledgeRepository.find("ID", edge.getPREDECESSORNODE()).firstResult())
                + "\"" + "[labelType=\"html\" label=\" <span style='color:"
                + predicate.getCOLORNAME() + ";'>" + predicate.getPNAME()
                + "</span> \"]\n";
    }

    public String myCreate(Edgeamongknowledge edgeamongknowledge) {
        String result;
        //检查该记录是否已经存在的一个解决办法是从subject获得所有的对应的knowledge，然后检查对应的前驱与后继的edgeAmongknowledge,
        //并放入SET中，然后从set中查找要create的记录，如果存在，则不create
        //但这可能会带来一个问题：随着课程这的切换，会反复从数据库读入该课程对应的所有边，带来数据库中大量记录的扇入与扇出
        //反而会增加内存与数据库带宽负担
        //因此，放弃这种方法，而用sql语句实现
        if (find("select * from Edgeamongknowledge where  Successornode=" + edgeamongknowledge.getSUCCESSORNODE()
                + " and Predecessornode=" + edgeamongknowledge.getPREDECESSORNODE()
                + " and predicate=" + edgeamongknowledge.getPREDICATE()
        ).list().isEmpty()) {
            create(edgeamongknowledge);
            result = "Succeed";
        } else {
            result = "Already Exist";
        }
        return result;
    }

    //  int i = 0;
    public void completePreKnowledgeSelection(Knowledge knowledge, HashSet<Knowledge> nowSelectedKnowledges_B) {
        //原来的
        Set<Knowledge> existedKnowledges_A = knowledgeRepository.getPredcessorKnowledges(knowledge);
        //得到要删除的
        Set<Knowledge> removedKnowledges = new HashSet<>(existedKnowledges_A);
        removedKnowledges.removeAll(nowSelectedKnowledges_B);
        //执行删除
        removedKnowledges.forEach((knowledge1) -> {
            delete("delete from edgeamongknowledge where successornode=" + knowledge.getID()
                    + " and predecessornode=" + knowledge1.getID());
        });
        //得到要添加的
        nowSelectedKnowledges_B.removeAll(existedKnowledges_A);
        nowSelectedKnowledges_B.forEach((Knowledge knowledge1) -> {
            if (null != knowledge.getID()) {
                Edgeamongknowledge edgeAmongknowledge = new Edgeamongknowledge();
                edgeAmongknowledge.setSUCCESSORNODE(knowledge.getID());
                edgeAmongknowledge.setPREDECESSORNODE(knowledge1.getID());
                create(edgeAmongknowledge);
            }
        });
    }

    //  int i = 0;


    public void completePredicateKnowledge(Knowledge knowledge, Collection<Edgeamongknowledge> edgeamongknowledgesSet) {
        //把新的添加进来，把旧的删除出去
        Set<Edgeamongknowledge> existedKnowledges_A = new HashSet<>(new HashSet<>(getEdgeamongknowledges4KnowledgePreOrSucc(knowledge.getID(), StaticFields.PREDCESSOR)));
        List<Edgeamongknowledge> toberemoved = new LinkedList<>();
        existedKnowledges_A.forEach(edge -> {
            Edgeamongknowledge tem = this.contains(edgeamongknowledgesSet, edge);
            if (null == tem) {// 新的集合中不包含该元素，所以需要删除
                toberemoved.add(edge);
            }
        });
        //再求需要添加的
        List<Edgeamongknowledge> tobeadded = new LinkedList<>();
        edgeamongknowledgesSet.forEach(edge -> {//id不一样，所以不能直接用removeAll，而采用检查是否存在的办法
            Edgeamongknowledge tem = this.contains(existedKnowledges_A, edge);
            if (null == tem) {//旧的集合中不存在这个新的，那么是需要添加的
                tobeadded.add(edge);//共同都有的，需要保留，不需要再create了
            }
        });

        //删除要删除的
        toberemoved.forEach(edge -> {
            destroy(edge);
        });
        tobeadded.forEach(edge -> {
            create(edge);
        });
    }

    public String cutEdge(Knowledge currentKnowledge, Subject subject) {
        if (!(currentKnowledge.getSUBJECT_ID().equals(subject.getID()))) {
            //1. get current subject
            //2. get knowledge of this subject
            //3. get edges contain these knowledges
            //4. remove those edges that precessor and successor are from different subject
            Set<Edgeamongknowledge> toBeRemoved = new HashSet<>();
            //1. get current subject
            //2. get knowledge of this subject
            List<Knowledge> subjectKnowledges = knowledgeRepository.getKnowledgeList4Subject(subject);
            //3. get edges contain these knowledges
            for (Knowledge knowledge : subjectKnowledges) {
                Set<Edgeamongknowledge> edgeamongknowledges =
                        new HashSet<>(getEdgeamongknowledgeList4Subject(subject));
                for (Edgeamongknowledge edgeamongknowledge : edgeamongknowledges) {
                    if (!knowledgeRepository.find("ID", edgeamongknowledge.getPREDECESSORNODE()).firstResult().getSUBJECT_ID().equals(subject.getID())) {
                        toBeRemoved.add(edgeamongknowledge);
                    }
                }
                Set<Edgeamongknowledge> edgeamongknowledges1 =
                        new HashSet<>(getEdgeamongknowledges4KnowledgePreOrSucc(knowledge.getID(), StaticFields.SUCCESSOR));
                for (Edgeamongknowledge edgeamongknowledge : edgeamongknowledges1) {
                    if (!knowledgeRepository.find("ID", edgeamongknowledge.getSUCCESSORNODE()).firstResult().getSUBJECT_ID().equals(subject.getID())) {
                        toBeRemoved.add(edgeamongknowledge);
                    }
                }
            }
            //4. remove those edges that precessor and successor are from different subject
            for (Edgeamongknowledge edgeamongknowledge : toBeRemoved) {
                destroy(edgeamongknowledge);
            }
            return "Succeed";
        }
        return "Failed";
    }

    private Edgeamongknowledge contains(Collection<Edgeamongknowledge> knowledgeSet, Edgeamongknowledge edge) {
        for (Edgeamongknowledge ekl : knowledgeSet) {
            if (ekl.getPREDECESSORNODE().equals(edge.getPREDECESSORNODE()) && ekl.getSUCCESSORNODE().equals(edge.getSUCCESSORNODE()) && ekl.getPREDICATE().equals(edge.getPREDICATE())) {
                return ekl;
            }
        }
        return null;
    }

    public void removeDuplicate() {
        //查找重复记录，并删除
        HashMap<EdgeAmongKnowledgeWithoutId, Integer> record = new HashMap<>();
        List<Edgeamongknowledge> allEdgeamongknowledges = listAll();
        List<Edgeamongknowledge> removed = new LinkedList<>();
        allEdgeamongknowledges.forEach(edge -> {
            EdgeAmongKnowledgeWithoutId tem = new EdgeAmongKnowledgeWithoutId();
            tem.preKnowledge = edge.getPREDECESSORNODE();
            tem.succKnowledge = edge.getSUCCESSORNODE();
            tem.predicate = edge.getPREDICATE();
            if (record.containsKey(tem)) {
                record.put(tem, record.get(tem) + 1);
                removed.add(edge);
            } else {
                record.put(tem, 1);
            }
        });
        for (Edgeamongknowledge edge : removed) {
            destroy(edge);
        }
    }

    static class EdgeAmongKnowledgeWithoutId {
        Integer preKnowledge, succKnowledge;
        Integer predicate;
    }

}
